package org.ainlolcat.ainscience.metaentity;

import org.ainlolcat.ainscience.Controller;
import org.ainlolcat.ainscience.UpdateListener;
import org.ainlolcat.ainscience.entity.Entity;
import org.ainlolcat.ainscience.entity.links.Link;
import org.ainlolcat.ainscience.entity.SimpleEntityParser;
import org.ainlolcat.ainscience.matrix.*;
import org.ainlolcat.ainscience.project.ProjectFileHandler;
import org.ainlolcat.ainscience.templates.Template;
import org.ainlolcat.ainscience.tools;
import org.ainlolcat.ainscience.utils.PathUtils;
import org.ainlolcat.ctp.util.IDGenerator;
import org.apache.log4j.Logger;
import org.jdom.Element;

import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.Map;

/**
 * @author ainlolcat
 * Date: 12/8/11
 */
public class MultifileMetaEntityParser extends MulticolumnMetaEntityParser{
    private static Logger log = Logger.getLogger(MultifileMetaEntityParser.class);

    @Override
    protected MetaEntity loadInternal() throws IOException {
        String path = desc.getAttributeValue("path");

        boolean re;
        String search;
        if (metaEntityDescription.getChild("filename").getAttributeValue("re") == null){
            re = false;
            search = metaEntityDescription.getChild("filename").getAttributeValue("postfix");
        } else{
            re = true;
            search = metaEntityDescription.getChild("filename").getAttributeValue("re");
        }
        boolean seekindeep =
                metaEntityDescription.getChild("seekindeep") != null ?
                        tools.parseBoolean(metaEntityDescription.getChild("seekindeep").getAttributeValue("value")):
                        true;
        File rootPath = new File(PathUtils.replaceMacros(path));
        log.debug(path+" => "+rootPath.getAbsolutePath());
        if (rootPath.isDirectory()){
            log.debug("dir");
            handleFolder(rootPath, seekindeep, re, search, template, type2regTemplate, type2reg);
        }
        MultifileMetaEntity sme = new MultifileMetaEntity(type, path, template);
        sme.setID(IDGenerator.getNextIntegerID());
        sme.setName(name);
        return sme;
    }

    private void handleFolder(File root, boolean goDeep, boolean re,String search, Template temp, String type2regTemplate, String type2reg){
        File[] child = root.listFiles();
        for(File file:child){
            try{
                if (file.isDirectory()&&goDeep){
                    log.debug("another dir: "+file.getAbsolutePath());
                    handleFolder(file, goDeep, re, search, temp, type2regTemplate, type2reg);
                } else {
                    log.debug("file: "+file.getAbsolutePath());
                    if (!re&&file.getName().endsWith(search)){
                        handleFile(file, temp, type2regTemplate, type2reg);
                    }
                    if (re&&file.getName().matches(search)){
                        handleFile(file, temp, type2regTemplate, type2reg);
                    }
                }
            }catch(IOException e){
                log.error(e);
            }
        }
    }

    private void handleFile(File root,Template template, String type2regTemplate, String type2reg) throws IOException {
        MatrixFile matrixs = new MatrixFileParser().parseFile(template.getMatrixParserParams(),root.getCanonicalPath());
        Matrix matrix = matrixs.getMatrix(0);
        if (metaEntityDescription.getChildren("column") != null)
            handleNextColumnSet(metaEntityDescription.getChildren("column"), matrix, root.getName(), 0);
        else {
            Element e = prepareEntityDefinition(root.getName(), type2reg, type2regTemplate, desc.getChildren());
            Entity se = new SimpleEntityParser().load(matrix,e);
            Controller.getInstance().getProject().addEntity(se);
        }
    }

    protected boolean handleNextColumnSet(List<Element> columns, Matrix source, String filename, int currentNum){
        boolean hasNext = true;
        Matrix temp = new Matrix();
        for (Element e: columns){
            hasNext = handleColumnDefinition(e, currentNum, source, temp);
            if (!hasNext)
                break;
        }
        if (!hasNext)
            return hasNext;

        Map<String, Link> links = tools.parseLinks(desc.getChildren("link"), new MatrixEntityWrapper(temp));

        new MatrixCalculator().calculate(temp, metaEntityDescription, links);

        try{
            Element e = prepareEntityDefinition(filename, type2reg, type2regTemplate, desc.getChildren());
            Entity se = new SimpleEntityParser().load(temp,e);
            Controller.getInstance().getProject().addEntity(se);
            Controller.getInstance().throwUpdateEvent(se, UpdateListener.CREATE_ENTITY_ACTION);
        } catch (Exception ex){
            log.error("Cannot load next entity in " +
                    "\n\tFile: " + filename +
                    "\n\tColumn count: " + temp.getColumnCount()
                    , ex);
        }
        return hasNext;
    }

    //<metaentity name="Entity Loader" id="401" templateID="103" entityType="spectr_loader" path="%HOME%/spectr/"/>
    public Element save(MetaEntity current) throws UnsupportedMetaEntityTypeException {
        if (current instanceof MultifileMetaEntity){
            Element entity = new Element(ProjectFileHandler.META_ENTITY_TAG);
            entity.setAttribute(ProjectFileHandler.ENTITY_ATTR_NAME,current.getName());
            entity.setAttribute(ProjectFileHandler.ENTITY_ATTR_ID, current.getID().toString());
            entity.setAttribute(ProjectFileHandler.ENTITY_ATTR_TEMPLATE_NAME, current.getTemplate().getName());
            entity.setAttribute(ProjectFileHandler.ENTITY_ATTR_ENTITY_TYPE, current.getType());
            entity.setAttribute(ProjectFileHandler.META_ENTITY_PATH_TAG,((MultifileMetaEntity) current).getPath());
            return entity;
        } else {
            throw new UnsupportedMetaEntityTypeException();
        }
    }
}
